package com.erp.erp_ui.warehouse.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.erp.enums.ContractTypeEnum;
import com.erp.enums.OperationStatusEnum;
import com.erp.enums.ProductTypeEnum;
import com.erp.erp_entitys.business.entity.OfferEntity;
import com.erp.erp_entitys.business.entity.TaskEntity;
import com.erp.erp_entitys.business.req.CarryDetailStatisticsPaymentReq;
import com.erp.erp_entitys.business.req.TaskPageListInfoReq;
import com.erp.erp_entitys.business.rsp.StatisticsCarryDetailPaymentRsp;
import com.erp.erp_entitys.warehouse.entity.StockDetailEntity;
import com.erp.erp_entitys.warehouse.entity.StockEntity;
import com.erp.erp_entitys.warehouse.entity.WarehouseRentEntity;
import com.erp.erp_entitys.warehouse.req.QueryStockProductReq;
import com.erp.erp_entitys.warehouse.req.RentalFeePageListReq;
import com.erp.erp_entitys.warehouse.req.StockAccountAgeReq;
import com.erp.erp_entitys.warehouse.req.StockReq;
import com.erp.erp_servers.warehouse.IStockDetailService;
import com.erp.erp_servers.warehouse.IStockService;
import com.erp.erp_servers.warehouse.IWarehouseRentService;
import com.erp.erp_ui.business.req.TaskPageListReq;
import com.erp.erp_ui.business.vo.StatisticsCarryDetailPaymentVo;
import com.erp.erp_ui.business.vo.TaskPageListVo;
import com.erp.erp_ui.money.req.OperationReq;
import com.erp.erp_ui.warehouse.enums.DataIsValidEnum;
import com.erp.erp_ui.warehouse.enums.WarehouseRentStatusEnum;
import com.erp.erp_ui.warehouse.req.AccountAgeReq;
import com.erp.erp_ui.warehouse.req.AddRentalFeeReq;
import com.erp.erp_ui.warehouse.req.SelectStockReq;
import com.erp.erp_ui.warehouse.req.StockProductReq;
import com.erp.erp_ui.warehouse.vo.*;
import com.erp.utils.DateUtils;
import com.erp.utils.R;
import com.erp.utils.ResultStatusEnum;
import com.erp.utils.StringUtil;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;

/**
 * @ClassName : StockService
 * @Description : 库存业务逻辑层
 * @Author : lst
 * @Date: 2020-07-15 08:29
 */
@Service
public class StockService {

    /**
     * 库存接口
     */
    private final IStockService iStockService;

    /**
     * 库存明细接口
     */
    private final IStockDetailService iStockDetailService;

    /**
     * 海外仓库租金接口
     */
    private final IWarehouseRentService warehouseRentService;

    @Autowired
    public StockService(IStockService iStockService,
                        IStockDetailService iStockDetailService,
                        IWarehouseRentService warehouseRentService) {
        this.iStockService = iStockService;
        this.iStockDetailService = iStockDetailService;
        this.warehouseRentService = warehouseRentService;
    }

    /**
     * 60天
     */
    private static final Integer SIXTY = 60;

    /**
     * 180天
     */
    private static final Integer ONE_HUNDRED_EIGHTY = 180;

    /**
     * 360天
     */
    private static final Integer THREE_HUNDRED_SIXTY = 360;

    /**
     * 720天
     */
    private static final Integer SEVEN_HUNDRED_TWENTY = 720;

    /**
     * 获取库存集合
     *
     * @param req
     * @return
     */
    public PageInfo<StockVo> getStockList(SelectStockReq req) {
        //获取库存数据
        List<StockEntity> stockList = getStockListByQuery(req);
        //获取分页信息
        PageInfo stockPageInfo = new PageInfo(stockList);
        //处理返回数据
        stockPageInfo.setList(getEncapsulationStockList(stockList));
        return stockPageInfo;
    }

    /**
     * 处理返回数据
     * @param stockList 待处理的数据集合
     * @return 处理后的数据集合
     */
    private List<StockVo> getEncapsulationStockList(List<StockEntity> stockList){
        List<StockVo> stockVos = new ArrayList<>();
        if(CollectionUtils.isEmpty(stockList)){
            return stockVos;
        }
        for(StockEntity stock : stockList){
            StockVo stockVo = new StockVo();
            //赋值
            BeanUtils.copyProperties(stock, stockVo);
            //创建日期转换
            stockVo.setCreateDate(DateUtils.format(stock.getCreateDate(), DateUtils.DATE_PATTERN));
            //入库日期转换
            stockVo.setInStoreDate(DateUtils.format(stock.getInStoreDate(), DateUtils.DATE_PATTERN));
            //产品类型转换
            stockVo.setProductType(ProductTypeEnum.getDescById(stock.getProductType()));
            //合同类型转换
            stockVo.setContractType(ContractTypeEnum.getDescById(stock.getContractType()));

            stockVos.add(stockVo);
        }
        return stockVos;
    }

    /**
     * 获取库存数据
     * @param req 查询参数
     * @return 库存数据
     */
    private List<StockEntity> getStockListByQuery(SelectStockReq req){
        StockReq stockReq = new StockReq();
        BeanUtils.copyProperties(req, stockReq);
        //查询日期(入库日期)
        if (StringUtils.isNotEmpty(req.getFindDate())) {
            stockReq.setInStoreDate(req.getFindDate());
        }
        //合同号
        if(StringUtils.isNotEmpty(req.getContractNo())){
            //去除前后空格
            stockReq.setContractNo(req.getContractNo().trim());
        }
        //产品编码
        if(StringUtils.isNotEmpty(req.getProductCode())){
            //去除前后空格
            stockReq.setProductCode(req.getProductCode().trim());
        }
        //规格编码
        if(StringUtils.isNotEmpty(req.getSpecificationCode())){
            //去除前后空格
            stockReq.setSpecificationCode(req.getSpecificationCode().trim());
        }
        //中文名称
        if(StringUtils.isNotEmpty(req.getProductCName())){
            //去除前后空格
            stockReq.setProductCName(req.getProductCName().trim());
        }
        //英文名称
        if(StringUtils.isNotEmpty(req.getProductEName())){
            //去除前后空格
            stockReq.setProductEName(req.getProductEName().trim());
        }
        //批次
        if(StringUtils.isNotEmpty(req.getLotNo())){
            //去除前后空格
            stockReq.setLotNo(req.getLotNo().trim());
        }
        //入库单号
        if(StringUtils.isNotEmpty(req.getInStoreBillNo())){
            //去除前后空格
            stockReq.setLotNo(req.getInStoreBillNo().trim());
        }
        //默认查询条件为模糊查询
        stockReq.setLikeContractNo(0);
        stockReq.setLikeProductCode(0);
        stockReq.setLikeSpecificationCode(0);
        stockReq.setLikeProductCName(0);
        stockReq.setLikeProductEName(0);
        stockReq.setLikeLotNo(0);
        stockReq.setLikeInStoreBillNo(0);

        return iStockService.getStockList(stockReq);
    }

    /**
     * 通过父id获取库存明细
     * @param id
     * @return
     */
    public PageInfo<StockDetailVo> getStockDetailById(Integer id){
        if(null == id){
           return null;
        }
        List<StockDetailEntity> stockDetailEntities = iStockDetailService.queryByParentId(id);
        PageInfo stockDetailPageInfo = new PageInfo(stockDetailEntities);
        List<StockDetailVo> stockDetailVos = new ArrayList<>();
        for(StockDetailEntity stockDetailEntity : stockDetailEntities){
            StockDetailVo stockDetailVo = new StockDetailVo();
            BeanUtils.copyProperties(stockDetailEntity, stockDetailVo);
            //创建时间转换
            stockDetailVo.setCreateDate(DateUtils.format(stockDetailEntity.getCreateDate(), DateUtils.DATE_PATTERN));

            stockDetailVos.add(stockDetailVo);
        }
        stockDetailPageInfo.setList(stockDetailVos);
        return stockDetailPageInfo;
    }

    /**
     * 获取库存账龄
     * @param req 查询参数
     * @return 库存账龄
     * @throws ParseException
     */
    public PageInfo<StockAccountAgeVo> getStockGoodsAge(AccountAgeReq req) throws ParseException {
        //初始化查询参数
        StockAccountAgeReq ageReq = new StockAccountAgeReq();
        BeanUtils.copyProperties(req, ageReq);

        //设置货龄区间(入库开始、结束时间)
        setInStockTime(req.getGoodsAge(), ageReq);

        //获取账龄数据
        List<StockEntity> stocks = iStockService.getStockAccountAgeList(ageReq);
        PageInfo stockDetailPageInfo = new PageInfo(stocks);
        //初始化回参
        List<StockAccountAgeVo> ageVos = new ArrayList<>();
        if (stocks.isEmpty()) {
            stockDetailPageInfo.setList(ageVos);
            return stockDetailPageInfo;
        }
        for (StockEntity stock : stocks) {
            StockAccountAgeVo ageVo = new StockAccountAgeVo();
            //赋值
            BeanUtils.copyProperties(stock, ageVo);
            //合同类型
            ageVo.setContractTypeStr(ContractTypeEnum.getDescById(stock.getContractType()));
            //设置库存账龄(天)
            int accountAge = DateUtils.daysBetween(stock.getInStoreDate(), new Date());
            ageVo.setStockAccountAge(accountAge);
            //设置账龄区间信息
            getGoodsAccountAge(accountAge, stock.getRealQuantity(), ageVo);

            ageVos.add(ageVo);
        }
        stockDetailPageInfo.setList(ageVos);
        return stockDetailPageInfo;

    }

    /**
     * 设置账龄区间信息
     * 货龄区间(1、小于60天 2、60至180天 3、180天至一年 4、一年至两年 5、两年以上)
     * @param accountAge   库存账龄(天)
     * @param realQuantity 库存数量
     * @param ageVo 返回对象实体
     */
    private void getGoodsAccountAge(int accountAge, BigDecimal realQuantity, StockAccountAgeVo ageVo) {
        if (accountAge < SIXTY) {
            //小于60天
            ageVo.setLessThanSixtyDays(realQuantity);
            //60至180天
            ageVo.setOneHundredEighty(new BigDecimal("0"));
            //180天至一年
            ageVo.setThreeHundredSixty(new BigDecimal("0"));
            //一年至两年
            ageVo.setSevenHundredTwenty(new BigDecimal("0"));
            //两年以上
            ageVo.setMoreThanTwoYears(new BigDecimal("0"));
        } else if (accountAge >= SIXTY && accountAge < ONE_HUNDRED_EIGHTY) {
            //小于60天
            ageVo.setLessThanSixtyDays(new BigDecimal("0"));
            //60至180天
            ageVo.setOneHundredEighty(realQuantity);
            //180天至一年
            ageVo.setThreeHundredSixty(new BigDecimal("0"));
            //一年至两年
            ageVo.setSevenHundredTwenty(new BigDecimal("0"));
            //两年以上
            ageVo.setMoreThanTwoYears(new BigDecimal("0"));
        } else if (accountAge >= ONE_HUNDRED_EIGHTY && accountAge < THREE_HUNDRED_SIXTY) {
            //小于60天
            ageVo.setLessThanSixtyDays(new BigDecimal("0"));
            //60至180天
            ageVo.setOneHundredEighty(new BigDecimal("0"));
            //180天至一年
            ageVo.setThreeHundredSixty(realQuantity);
            //一年至两年
            ageVo.setSevenHundredTwenty(new BigDecimal("0"));
            //两年以上
            ageVo.setMoreThanTwoYears(new BigDecimal("0"));
        } else if (accountAge >= THREE_HUNDRED_SIXTY && accountAge < SEVEN_HUNDRED_TWENTY) {
            //小于60天
            ageVo.setLessThanSixtyDays(new BigDecimal("0"));
            //60至180天
            ageVo.setOneHundredEighty(new BigDecimal("0"));
            //180天至一年
            ageVo.setThreeHundredSixty(new BigDecimal("0"));
            //一年至两年
            ageVo.setSevenHundredTwenty(realQuantity);
            //两年以上
            ageVo.setMoreThanTwoYears(new BigDecimal("0"));
        } else {
            //小于60天
            ageVo.setLessThanSixtyDays(new BigDecimal("0"));
            //60至180天
            ageVo.setOneHundredEighty(new BigDecimal("0"));
            //180天至一年
            ageVo.setThreeHundredSixty(new BigDecimal("0"));
            //一年至两年
            ageVo.setSevenHundredTwenty(new BigDecimal("0"));
            //两年以上
            ageVo.setMoreThanTwoYears(realQuantity);
        }
    }

    /**
     * 设置库龄区间(入库区间)
     *
     * @param goodsAge 1、小于60天 2、60至180天 3、180天至一年 4、一年至两年 5、两年以上
     */
    private void setInStockTime(Integer goodsAge, StockAccountAgeReq ageReq) {
        if (null == goodsAge) {
            return;
        }
        switch (goodsAge) {
            case 1:
                //开始时间(近60天)
                ageReq.setStartTime(DateUtils.getPastDateByDay(60));
                //结束时间
                ageReq.setEndTime(DateUtils.format(new Date(), DateUtils.DATE_PATTERN));
                break;
            case 2:
                //开始时间(60至180天)
                ageReq.setStartTime(DateUtils.getPastDateByDay(180));
                //结束时间
                ageReq.setEndTime(DateUtils.getPastDateByDay(60));
                break;
            case 3:
                //开始时间(180天至一年)
                ageReq.setStartTime(DateUtils.getPastDateByYear(1));
                //结束时间
                ageReq.setEndTime(DateUtils.getPastDateByDay(180));
                break;
            case 4:
                //开始时间(一年至两年)
                ageReq.setStartTime(DateUtils.getPastDateByYear(2));
                //结束时间
                ageReq.setEndTime(DateUtils.getPastDateByYear(1));
                break;
            default:
                //结束时间
                ageReq.setEndTime(DateUtils.getPastDateByYear(2));
                break;
        }

    }

    /**
     * 获取库存产品信息
     * @param req 查询入参实体
     * @return 库存产品集合
     */
    public PageInfo<StockProductVo> getStockProductByPage(StockProductReq req){
        //初始化查询参数实体
        QueryStockProductReq queryStockProductReq = new QueryStockProductReq();
        //赋值
        BeanUtils.copyProperties(req, queryStockProductReq);
        //查询
        List<StockEntity> stocks = iStockService.getStockProductList(queryStockProductReq);
        //获取分页信息
        PageInfo stockDetailPageInfo = new PageInfo(stocks);
        //初始化回参实体集合
        List<StockProductVo> voList = new ArrayList<>();
        //遍历处理数据信息
        for(StockEntity stock : stocks){
            //初始化回参实体
            StockProductVo stockProductVo = new StockProductVo();
            //字段赋值
            BeanUtils.copyProperties(stock, stockProductVo);
            //入库日期转换
            stockProductVo.setInStoreDate(DateUtils.format(stock.getInStoreDate(), DateUtils.DATE_PATTERN));
            //合同类型(1:内销 2:外销 3:待定)
            stockProductVo.setContractTypeStr(ContractTypeEnum.getDescById(stock.getContractType()));

            voList.add(stockProductVo);
        }

        stockDetailPageInfo.setList(voList);

        return stockDetailPageInfo;
    }

    /**
     * 海外仓库租金费-新增
     * @param req 新增信息对象
     * @param name 当前操作员名称
     * @param code 当前操作员编码
     * @return 新增结果
     */
    public R addRentalFeeInfo(AddRentalFeeReq req, String name, String code) throws ParseException {
        //初始化仓库租金费对象
        WarehouseRentEntity warehouseRent = new WarehouseRentEntity();
        //赋值
        BeanUtils.copyProperties(req, warehouseRent);
        //执行日期处理
        warehouseRent.setExecutionDate(DateUtils.convertStringToDate(req.getExecutionDate(), DateUtils.DATE_PATTERN));
        //创建日期
        warehouseRent.setCreateDate(new Date());
        //操作员名称
        warehouseRent.setOperationName(name);
        //操作员编码
        warehouseRent.setOperationCode(code);
        //状态(1.草稿 2.已启动 3.已停止)
        warehouseRent.setStatus(WarehouseRentStatusEnum.DRAFT.getId());
        //数据默认有效
        warehouseRent.setValid(DataIsValidEnum.VALID.getId());

        //调用接口新增
        warehouseRentService.insert(warehouseRent);
        return R.buildError(ResultStatusEnum.SUCCESS);
    }

    /**
     * 首页-分页列表-海外仓库租金费
     * @param req 查询参数
     * @return 海外仓库租金费
     */
    public PageInfo<RentalFeePageListVo> getRentalFeeInfoByPage(RentalFeePageListReq req){
        //初始化回参对象集合
        List<RentalFeePageListVo> voList = new ArrayList<>();
        //调用接口查询结果
        List<WarehouseRentEntity> rentalList = warehouseRentService.getRentalFeeListByQuery(req);
        PageInfo pageInfo = new PageInfo(rentalList);
        if(CollectionUtils.isEmpty(rentalList)){
            pageInfo.setList(voList);
            return pageInfo;
        }
        for(WarehouseRentEntity rental : rentalList){
            RentalFeePageListVo vo = new RentalFeePageListVo();
            //赋值
            BeanUtils.copyProperties(rental, vo);
            //启动日期
            vo.setExecutionDate(DateUtils.format(rental.getExecutionDate()));
            //状态
            vo.setStatusStr(WarehouseRentStatusEnum.getDescById(rental.getStatus()));

            voList.add(vo);
        }

        pageInfo.setList(voList);
        return pageInfo;
    }

    /**
     * 海外仓库费-箱体操作
     * @param req 操作对象
     * 1.删除 2.执行 3.终止
     */
    public R operation(OperationReq req){
        if(null == req.getId() || null == req.getOperation()){
            return R.buildError(ResultStatusEnum.SYSTEM_ERROR);
        }
        WarehouseRentEntity warehouseRent = new WarehouseRentEntity();
        //设置修改主键
        warehouseRent.setId(req.getId());
        //修改时间
        warehouseRent.setModifyTime(new Date());

        switch (req.getOperation()){
            case 1:
                //删除后,数据设为无效
                warehouseRent.setValid(DataIsValidEnum.INVALID.getId());
                break;
            case 2:
                //执行,状态改为已启动
                warehouseRent.setStatus(WarehouseRentStatusEnum.ACTIVATED.getId());
                break;
            case 3:
                //终止,状态改为已停止
                warehouseRent.setStatus(WarehouseRentStatusEnum.STOPPED.getId());
                break;
        }
        //调用接口修改
        warehouseRentService.update(warehouseRent);
        return R.buildError(ResultStatusEnum.SUCCESS);
    }

    /**
     * 按出运明细统计采购付款信息-导出
     * @param req
     * @return
     */
    public JSONObject getStockExport(SelectStockReq req){
        //获取库存数据
        List<StockEntity> stockList = getStockListByQuery(req);
        //处理返回数据
        List<StockVo> stockVos = getEncapsulationStockList(stockList);

        JSONObject obj = new JSONObject();
        //获取excel的title信息
        JSONArray titleList = getTitleInfo(req.getShow());
        JSONArray data = new JSONArray();
        data.add(titleList);
        if(CollectionUtils.isEmpty(stockVos)){
            obj.put("data", data);
            return obj;
        }
        //处理导出Excel的数据
        setEncapsulationStockList(data, stockVos, req.getShow());

        obj.put("data", data);

        return obj;
    }

    /**
     * 处理导出Excel的数据
     * @param data 处理后的数据
     * @param list 数据源
     * @param show 是否隐藏部分字段
     */
    public void setEncapsulationStockList(JSONArray data, List<StockVo> list, boolean show) {
        for (StockVo vo : list) {
            JSONArray infoList = new JSONArray();
            infoList.add(getNotNullOfStringInfo(vo.getLotNo()));
            infoList.add(getNotNullOfStringInfo(vo.getProductCode()));
            infoList.add(getNotNullOfStringInfo(vo.getSpecificationCode()));
            infoList.add(getNotNullOfStringInfo(vo.getSpecificationExplanation()));
            infoList.add(getNotNullOfStringInfo(vo.getWarehouseName()));
            infoList.add(getNotNullOfStringInfo(vo.getContractNo()));
            infoList.add(getNotNullOfStringInfo(vo.getContractType()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getRealQuantity()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getRealAvailableQuantity()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getCanApplyQuantity()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getOutWarehouseApply()));
            if(show){
                infoList.add(getNotNullOfStringInfo(vo.getSupplierName()));
            }
            infoList.add(getNotNullOfStringInfo(vo.getClientProductNo()));
            infoList.add(getNotNullOfStringInfo(vo.getProductUnit()));
            infoList.add(getNotNullOfStringInfo(vo.getProductCname()));
            infoList.add(getNotNullOfStringInfo(vo.getProductEname()));
            infoList.add(getNotNullOfStringInfo(vo.getProductCdesc()));
            infoList.add(getNotNullOfStringInfo(vo.getProductEdesc()));
            infoList.add(getNotNullOfStringInfo(vo.getColor()));
            infoList.add(getNotNullOfStringInfo(vo.getSalesman()));
            infoList.add(getNotNullOfStringInfo(vo.getSalesmanCode()));
            if(show){
                infoList.add(getNotNullOfBigDecimalInfo(vo.getCostAmount()));
                infoList.add(getNotNullOfBigDecimalInfo(vo.getProductUnitPrice()));
            }
            infoList.add(getNotNullOfStringInfo(vo.getMemo()));
            infoList.add(getNotNullOfStringInfo(vo.getCreateDate()));
            infoList.add(getNotNullOfStringInfo(vo.getInStoreDate()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getShareCostPrice()));
            infoList.add(getNotNullOfStringInfo(vo.getPurchaseNo()));
            infoList.add(getNotNullOfStringInfo(vo.getInStoreBillNo()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getTrayNumber()));
            infoList.add(getNotNullOfBigDecimalInfo(vo.getTotalTray()));
            infoList.add(getNotNullOfStringInfo(vo.getProductType()));

            data.add(infoList);
        }
    }

    /**
     * 获取String类型不为空数据
     * @param value 目标数据
     * @return 不为空数据
     */
    private String getNotNullOfStringInfo(String value){
        if(StringUtils.isEmpty(value)){
            return "";
        }else {
            return value;
        }
    }

    /**
     * 获取BigDecimal类型不为空的数据
     * @param value 目标数据
     * @return 不为空数据
     */
    private BigDecimal getNotNullOfBigDecimalInfo(BigDecimal value){
        if(StringUtil.isNotEmpty(value)){
            return value;
        }else {
            return new BigDecimal("0");
        }
    }

    /**
     * 获取导出Excel的库存表头信息
     * @param show 是否隐藏部分字段
     * @return Excel表头信息
     */
    public JSONArray getTitleInfo(boolean show) {
        JSONArray obj = new JSONArray();
        obj.add("批次号");
        obj.add("产品编码");
        obj.add("规格编码");
        obj.add("规格说明");
        obj.add("仓库名称");
        obj.add("合同号");
        obj.add("合同类型");
        obj.add("实际数量");
        obj.add("实际可用数量");
        obj.add("可申请数量");
        obj.add("出库申请数量");
        if(show){
            obj.add("供应商名称");
        }
        obj.add("客户货号");
        obj.add("产品单位");
        obj.add("产品中文名称");
        obj.add("产品英文名称");
        obj.add("产品中文描述");
        obj.add("产品英文描述");
        obj.add("颜色");
        obj.add("业务员");
        obj.add("业务员编码");
        if(show){
            obj.add("成本金额小计");
            obj.add("成本单价");
        }
        obj.add("备注");
        obj.add("创建日期");
        obj.add("入库日期");
        if(show){
            obj.add("分摊费用单价");
        }
        obj.add("采购单号");
        obj.add("入库单号");
        obj.add("托盘入数");
        obj.add("总托盘");
        obj.add("产品类型");

        return obj;
    }
}
